package com.study.kt._04project.game_tank

import com.study.kt._04project.game_tank.business.*
import com.study.kt._04project.game_tank.enums.Direction
import com.study.kt._04project.game_tank.model.*
import com.study.kt.project.game_tank.model.*
import javafx.scene.input.KeyCode
import javafx.scene.input.KeyEvent
import org.itheima.kotlin.game.core.Window
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.concurrent.CopyOnWriteArrayList

class GameWindow : Window("坦克大战", "img/bomb.gif", Config.gameWidth, Config.gameWidth) {

    //private val views = arrayListOf<View>()

    //View是否可以被回收在耗时线程中操作，集合在主线程定义，如果进行增删会造成线程同步问题
    //使用线程安全的集合可以解决
    private val views = CopyOnWriteArrayList<View>()

    //lateinit延迟创建
    private lateinit var tank: Tank

    override fun onCreate() {
        //绘制地图中的元素(新建map文件放图片的地方标注，不放图片的地方用空代替)
        //打包后，resoureces文件夹中内容打包进jar包，而使用File无法读取到jar中内容
        //val file = File(javaClass.getResource("/map/1.map").path)
        val fileInputStream = javaClass.getResourceAsStream("/map/1.map")
        val file = BufferedReader(InputStreamReader(fileInputStream, "utf-8"))
        val lines = file.readLines()
        //如果找到"砖"字则换一个砖
        var lineNum = 0 //行
        lines.forEach {
            //拿到每一行
            var colmnNum = 0 //列
            it.toCharArray().forEach {
                //拿到每个字
                when (it) {
                    '砖' -> views.add(Wall(colmnNum * Config.block, lineNum * Config.block))
                    '铁' -> views.add(Steel(colmnNum * Config.block, lineNum * Config.block))
                    '草' -> views.add(Grass(colmnNum * Config.block, lineNum * Config.block))
                    '水' -> views.add(Water(colmnNum * Config.block, lineNum * Config.block))
                    '敌' -> views.add(Enemy(colmnNum * Config.block, lineNum * Config.block))
                }
                colmnNum++
            }
            lineNum++
        }

        //添加我方坦克
        tank = Tank(Config.block * 3, Config.block * 12)
        views.add(tank)

        //添加我方大本营
        views.add(Camp(Config.gameWidth / 2 - Config.block, Config.gameHeight - 96))
    }

    override fun onDisplay() {
        views.forEach {
            it.draw()
        }
    }

    override fun onKeyPressed(event: KeyEvent) {
        when (event.code) {
            //坦克向上运动
            KeyCode.UP -> {
                tank.move(Direction.UP)
            }
            KeyCode.DOWN -> {
                tank.move(Direction.DOWN)
            }
            KeyCode.LEFT -> {
                tank.move(Direction.LEFT)
            }
            KeyCode.RIGHT -> {
                tank.move(Direction.RIGHT)
            }
            KeyCode.Z -> {
                //发射子弹
                val bullet = tank.shoot()
                views.add(bullet)
            }
        }
    }

    override fun onRefresh() {
        //业务逻辑

        //判断坦克是否碰撞到墙
        //找出所有可移动的物体坦克
        views.filterIsInstance<Moveable>().forEach { move ->
            //找到所有的墙
            //记录碰撞的物体、方向
            var badBlock: Blockable? = null
            var badDirection: Direction? = null

            //此处过滤出障碍物，因为地方坦克自己也是障碍物，所以除了判断为障碍物还要加上不是移动的物体的条件
            views.filter { (it is Blockable) && (it != move) }.forEach blockTag@{ block ->
                //在迭代内部无法推断move、block的类型，所以需要强转
                block as Blockable

                //找到碰撞的物体，通知可移动的物体不可以继续移动
                val direction: Direction? = move.willCollision(block)
                direction?.let {
                    //如果direction不为空则执行let代码块，返回到第二层forEach
                    badBlock = block
                    badDirection = direction
                    return@blockTag
                }
            }
            move.notifyCollisition(badBlock, badDirection)
        }

        //找出可以自动移动的物体，让其启动
        views.filterIsInstance<AutoMoveable>().forEach {
            it.autoMove()
        }

        //如果是可被回收的View而且具备可回收的条件则回收
        views.filterIsInstance<Destoryable>().forEach {
            if (it.isDestory()) {
                views.remove(it)
            }
        }

        //判断是否遭受攻击
        views.filterIsInstance<Attachable>().forEach { attachable ->
            //过滤出受攻击者，而且攻击者的所有者不是受攻击者
            views.filter { (it is Sufferable) and (it != attachable.owner) }.forEach { sufferable ->
                sufferable as Sufferable
                if (attachable.isCollision(sufferable)) {
                    //找到攻击与被攻击的物体
                    attachable.notifyAttach(sufferable)
                    //被攻击后，返回一个View通知被攻击了
                    val blasts = sufferable.notifySuffer(attachable)

                    //如果有爆炸通知，则添加到views中显示
                    blasts?.let {
                        views.addAll(blasts)
                    }
                    //跳出内层循环
                    return@forEach
                }
            }
        }

        //找出自动射击的view，让其射击
        views.filterIsInstance<AutoShoot>().forEach {
            val view = it.autoShoot()
            view?.let {
                views.add(view)
            }
        }
    }
}